﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using tactics.Interfaces;
using tactics.Events;
using tactics.Commands;
using UnitShared;

namespace tactics
{
    #region Helper enums

    public enum DamageType
    {
        Invalid,
        Physical,
        Magic,
        Lightning,
        Frost,
        Fire,
        Poison,
        Holy,
        Dark,
    }

    public enum DefenseType
    {
        Physical,
        Magic,
    }

    #endregion

    public class Unit
    {
        public Vector3 worldPosition;

        string name;
        string faction;
        string description;
        List<string> types;
        int id;
        int x;
        int y;

        string texture;
        int pointCost;
        int hp;
        int speed;
        int attack;
        int magic;
        int defense;
        int magicDefense;
        int currentHp;
        int currentSpeed;
        int currentAttack;
        int currentMagic;
        int currentDefense;
        int currentMagicDefense;
        List<UnitTemplate.AbilityUses> abilities;
        string movementType;

        bool moved;
        bool acted;
        bool availableThisTurn;
        
        public event HitEventHandler UnitHit;
        public event MissEventHandler UnitMissed;

        List<IStatusEffect> statusEffects;

        #region properties

        public int Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }

        public int X
        {
            get
            {
                return x;
            }
            set
            {
                x = value;
            }
        }

        public int Y
        {
            get
            {
                return y;
            }
            set
            {
                y = value;
            }
        }
        
        public string Texture
        {
            get
            {
                return texture;
            }
            set
            {
                texture = value;
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public string Faction
        {
            get
            {
                return faction;
            }
            set
            {
                faction = value;
            }
        }

        public string Description
        {
            get
            {
                return description;
            }
            set
            {
                description = value;
            }
        }

        public List<string> Types
        {
            get
            {
                return types;
            }
            set
            {
                types = value;
            }
        }

        public int PointCost
        {
            get
            {
                return pointCost;
            }
            set
            {
                pointCost = value;
            }
        }

        public int Hp
        {
            get
            {
                return hp;
            }
        }

        public int Speed
        {
            get
            {
                return speed;
            }
        }

        public int Attack
        {
            get
            {
                return attack;
            }
        }

        public int Magic
        {
            get
            {
                return magic;
            }
        }

        public int Defense
        {
            get
            {
                return defense;
            }
        }

        public int MagicDefense
        {
            get
            {
                return magicDefense;
            }
        }

        public int CurrentHp
        {
            get
            {
                return currentHp;
            }
            set
            {
                currentHp = value;
            }
        }

        public int CurrentSpeed
        {
            get
            {
                return currentSpeed;
            }
            set
            {
                currentSpeed = value;
            }
        }

        public int CurrentAttack
        {
            get
            {
                return currentAttack;
            }
            set
            {
                currentAttack = value;
            }
        }

        public int CurrentMagic
        {
            get
            {
                return currentMagic;
            }
            set
            {
                currentMagic = value;
            }
        }

        public int CurrentDefense
        {
            get
            {
                return currentDefense;
            }
            set
            {
                currentDefense = value;
            }
        }

        public int CurrentMagicDefense
        {
            get
            {
                return currentMagicDefense;
            }
            set
            {
                currentMagicDefense = value;
            }
        }

        public List<UnitTemplate.AbilityUses> Abilities
        {
            get
            {
                return abilities;
            }
            set
            {
                abilities = value;
            }
        }

        public string MovementType
        {
            get
            {
                return movementType;
            }
            set
            {
                movementType = value;
            }
        }

        public bool Moved
        {
            get
            {
                return moved;
            }
            set
            {
                moved = value;
            }
        }

        public bool Acted
        {
            get
            {
                return acted;
            }
            set
            {
                acted = value;
            }
        }

        public bool AvailableThisTurn
        {
            get
            {
                return availableThisTurn;
            }
            set
            {
                availableThisTurn = value;
            }
        }

        public List<IStatusEffect> StatusEffects
        {
            get { return statusEffects; }
        }

        #endregion

        static int unitCount = 0;

        protected virtual void OnHitEvent(HitEventArgs e)
        {
            if (UnitHit != null)
                UnitHit(this, e);
        }

        protected virtual void OnMissEvent(MissEventArgs e)
        {
            if (UnitMissed != null)
                UnitMissed(this, e);
        }

        public Unit(UnitShared.UnitTemplate template)
        {
            id = unitCount++;
            name = template.Name;
            faction = template.Faction;
            description = template.Description;
            texture = template.Texture;
            pointCost = template.PointCost;            
            hp = template.Hp;
            speed = template.Speed;
            attack = template.Attack;
            magic = template.Magic;
            defense = template.Defense;
            magicDefense = template.MagicDefense;
            currentHp = template.Hp;
            currentSpeed = template.Speed;
            currentAttack = template.Attack;
            currentMagic = template.Magic;
            currentDefense = template.Defense;  
            currentMagicDefense = template.MagicDefense;
            movementType = template.MovementType;
            abilities = template.Abilities;
            moved = false;
            acted = false;
            availableThisTurn = true;

            //Build list of creature types
            string[] typeArray = template.Types.Split(',');
            types = new List<string>(typeArray);

            statusEffects = new List<IStatusEffect>();
        }

        public void TriggerHit()
        {
            OnHitEvent(new HitEventArgs(this));
        }

        public void TriggerMiss()
        {
            OnMissEvent(new MissEventArgs(this));
        }
        
        // system denotes if the game system is moving the unit, or if a player is.
        // when the system moves a unit (say in the event of a push-back), don't set the
        // units moved flag
        public void Move(int xIn, int yIn, bool system)
        {
            x = xIn;
            y = yIn;

            if (!system)
            {
                moved = true;
                availableThisTurn = false; //temp
            }
            else
            {
                worldPosition.X = xIn + 0.5f;
                worldPosition.Z = yIn + 0.5f;
            }
        }

        public void AddDamage(int amount, DamageType type)
        {
            //Check here against the list of immunities/resistances
            if (currentHp + amount > hp)
            {
                currentHp = hp;
            }
            else if(currentHp + amount <= 0)
            {
                currentHp = 0;
                //kill unit
                CommandQueue.Instance.AddCommand(new KillUnitCommand(this));
            }
            else
            {
                currentHp += amount;
            }
        }

        public void AddEffect(IStatusEffect effect)
        {
            statusEffects.Add(effect);
        }

        public void RemoveEffect(IStatusEffect effect)
        {
            statusEffects.Remove(effect);
        }

        public void Reset()
        {
            moved = false;
            acted = false;
            availableThisTurn = true;
            
            //Reset stats for status effects
            currentAttack = attack;
            currentDefense = defense;
            currentMagic = magic;
            currentMagicDefense = magicDefense;
            currentSpeed = speed;
            
            UpdateStatusEffects();
        }

        public void UpdateStatusEffects()
        {
            List<IStatusEffect> doneEffects = new List<IStatusEffect>();
            foreach(IStatusEffect effect in statusEffects)
            {
                effect.ProcessEffect(this);
                if (effect.Duration == 0)
                {
                    doneEffects.Add(effect);
                }
            }

            foreach (IStatusEffect effect in doneEffects)
            {
                RemoveEffect(effect);
            }
        }
    }
}